/* 
 * created by senllang 2023/12/24 
 * mail : study@senllang.onaliyun.com 
 *
 * Copyright (c) 2023-2024 senllang

 * This is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * 
 */
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define THREAD_NAME_LEN 32
typedef struct ThreadData
{
	char threadName[THREAD_NAME_LEN];
	unsigned long threadId;
}ThreadData;

__thread ThreadData *pthreadData = NULL;

void threadCleanUp(void* arg)
{
	char *str = (char *)arg;
	
	if(pthreadData != NULL)
	{
		printf("[%lu][%s]cleanup process (%s)\n", pthreadData->threadId, pthreadData->threadName, str);
		free(pthreadData);
		pthreadData = NULL;
	}
	else 
	{
		printf("[%lu] no work will be doing (%s). \n", pthread_self(), str);
	}

	return;
}

void* thr1Func(void* arg)
{
    char *parg = (char *)arg;

	pthreadData = (ThreadData *)malloc(sizeof(ThreadData));
	memset(pthreadData, sizeof(ThreadData), 0x00);

	strncpy(pthreadData->threadName, parg, THREAD_NAME_LEN);
	pthreadData->threadId = pthread_self();

	pthread_cleanup_push(threadCleanUp, (char*)"first handler");
	pthread_cleanup_push(threadCleanUp, (char*)"second handler");
    printf("[%lu][%s]cleanup process push completed. \n", pthreadData->threadId, pthreadData->threadName);

	/* cleanup process will not be running. */
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);

	return NULL;
}

void* thr2Func(void* arg)
{
	int ret = 2;
    char *parg = (char *)arg;

	pthreadData = (ThreadData *)malloc(sizeof(ThreadData));
	memset(pthreadData, sizeof(ThreadData), 0x00);

	strncpy(pthreadData->threadName, parg, THREAD_NAME_LEN);
	pthreadData->threadId = pthread_self();

	pthread_cleanup_push(threadCleanUp, (char*)"first handler");
	pthread_cleanup_push(threadCleanUp, (char*)"second handler");

    printf("[%lu][%s]cleanup process push completed. \n", pthreadData->threadId, pthreadData->threadName);

	/* make a error, exiting */
	if(ret == 2)
		pthread_exit(&ret);

	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
}


int main(int argc, char* argv[])
{
    int err;
	pthread_t	tid1, tid2, tid3;
	void	*ret;

	err = pthread_create(&tid1, NULL, thr1Func, "thread 1");
	if(0 != err)
		perror("can't create thread 1");

	err = pthread_create(&tid2, NULL, thr2Func, "thread 2");
	if(0 != err)
		perror("can't create thread 2");

 
	pthread_join(tid1, &ret);
	pthread_join(tid2, &ret);

	return 0;
}
